package com.tidy.seed.admin.system.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.tidy.seed.admin.system.service.FileUploadService;
import com.tidy.seed.configuration.FileUploadConfig;
import com.tidy.seed.admin.system.vo.file.upload.FileInfoVO;
import com.tidy.seed.admin.system.vo.file.upload.FileUploadVO;
import com.tidy.seed.util.ProfileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.*;

/**
 * 系统模块 - 文件上传服务实现
 */
@Service
public class FileUploadServiceImpl implements FileUploadService {

    @Resource
    private FileUploadConfig uploadConfig;  // 注入上传配置

    @Value("${custom.file-upload-prefix}")
    private String fileUploadPrefix;
    @Value("${custom.api-domain}")
    private String apiDomain;

    /**
     * 单文件上传实现
     */
    public FileUploadVO uploadSingle(MultipartFile file, String dir) throws Exception {
        // 1. 校验文件是否为空
        if (file.isEmpty()) {
            throw new Exception("上传文件不能为空");
        }
        String path = Paths.get(System.getProperty("user.dir"), uploadConfig.getRootPath()).toString();
        // 2. 计算存储路径
        String rootPath = ProfileUtils.isDev() ? path : uploadConfig.getRootPath();
        String dateDir = DateUtil.format(new Date(), "yyyy/MM/dd"); // 默认按日期
        String useDir = StrUtil.isNotBlank(dir) ? dir : dateDir;    // 优先用传入的 dir

        // 路径安全过滤，防止非法目录
        useDir = useDir.replaceAll("\\\\", "/") // 统一分隔符
                .replaceAll("\\.\\.", "") // 去掉 ..
                .replaceAll("/+", "/")    // 合并多斜杠
                .replaceAll("^/|/$", ""); // 去掉开头/结尾的斜杠

        String storageDir = Paths.get(rootPath + File.separator + useDir).toString();
        System.out.println("文件保存路径:" + storageDir);
        FileUtil.mkdir(storageDir); // 自动创建目录

        // 3. 生成唯一文件名
        String originalName = file.getOriginalFilename();
        String fileExt = FileUtil.extName(originalName);
        String fileName = IdUtil.fastSimpleUUID() + "." + fileExt;

        // 4. 保存文件
        File destFile = new File(storageDir, fileName);
        file.transferTo(destFile);
        //
        String accessPath = apiDomain + fileUploadPrefix + "/" + useDir + "/" + fileName;   // 访问路径
        // 5. 封装返回结果
        FileUploadVO result = new FileUploadVO();
        result.setFileName(originalName);                // 原始文件名
        result.setStorageName(fileName);                 // 存储文件名
        result.setFilePath(useDir + "/" + fileName);     // 相对路径
        result.setAccessPath(accessPath);                // 访问路径
        result.setFullPath(destFile.getAbsolutePath());  // 绝对路径
        result.setFileSize(file.getSize());              // 文件大小
        return result;
    }


    /**
     * 多文件上传实现
     */
    @Override
    public Map<String, Object> uploadMultiple(List<MultipartFile> files, String dir) throws Exception {
        if (files.isEmpty()) {
            throw new Exception("上传文件列表不能为空");
        }

        List<FileUploadVO> resultList = new ArrayList<>();
        for (MultipartFile file : files) {
            if (!file.isEmpty()) {
                resultList.add(uploadSingle(file, dir));  // 复用单文件上传逻辑
            }
        }

        // 封装多文件结果
        Map<String, Object> result = new HashMap<>();
        result.put("total", resultList.size());  // 总上传数
        result.put("success", resultList.size());  // 成功数（简化处理，实际需捕获单个异常）
        result.put("files", resultList);  // 详细文件信息
        return result;
    }

    /**
     * 逐级查询目录实现
     */
    @Override
    public Map<String, Object> listDir(String currentPath) throws Exception {
        // 1. 构建目录路径
        String rootPath = uploadConfig.getRootPath();
        File rootDir = new File(rootPath);
        File currentDir = new File(rootDir, currentPath);

        // 2. 校验路径合法性
        if (!currentDir.exists()) {
            throw new Exception("目录不存在：" + currentPath);
        }
        if (!currentDir.isDirectory()) {
            throw new Exception("路径不是文件夹：" + currentPath);
        }
        if (!isPathInRoot(currentDir, rootDir)) {
            throw new Exception("不允许访问根目录外的文件");
        }

        // 3. 查询当前目录下的一级文件
        File[] files = currentDir.listFiles();
        List<FileInfoVO> fileList = new ArrayList<>();
        if (files != null) {
            // 排序：文件夹在前，文件在后，按名称升序
            Arrays.sort(files, (f1, f2) -> {
                if (f1.isDirectory() && f2.isFile()) return -1;
                if (f1.isFile() && f2.isDirectory()) return 1;
                return f1.getName().compareTo(f2.getName());
            });

            // 转换为文件信息模型
            for (File file : files) {
                String accessPath = apiDomain + fileUploadPrefix + "/" + currentPath + "/" + file.getName();  // 访问路径
                FileInfoVO info = FileInfoVO.build(file, rootPath, accessPath);
                fileList.add(info);
            }
        }

        // 4. 封装返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("currentPath", currentPath);
        result.put("parentPath", getParentPath(currentPath));
        result.put("fileList", fileList);
        return result;
    }

    /**
     * 删除文件或文件夹
     */
    public void deletePath(String targetPath) throws Exception {
        String rootPath = uploadConfig.getRootPath();
        File rootDir = new File(rootPath);
        File targetFile = new File(rootDir, targetPath);
        System.err.println("测试打印:rootDir" + rootDir);
        System.err.println("测试打印:targetFile" + targetFile);
        // 1. 校验路径合法性
        if (!targetFile.exists()) {
            throw new Exception("文件或文件夹不存在：" + targetPath);
        }
        if (!isPathInRoot(targetFile, rootDir)) {
            throw new Exception("不允许删除根目录外的文件");
        }

        // 2. 执行删除（支持递归）
        boolean success = FileUtil.del(targetFile);
        if (!success) {
            throw new Exception("删除失败：" + targetPath);
        }
    }

    /**
     * 创建文件夹
     */
    public void createDir(String dirPath) throws Exception {
        String rootPath = uploadConfig.getRootPath();
        File rootDir = new File(rootPath);
        File targetDir = new File(rootDir, dirPath);

        // 1. 校验路径合法性
        if (targetDir.exists()) {
            throw new Exception("文件夹已存在：" + dirPath);
        }
        if (!isPathInRoot(targetDir, rootDir)) {
            throw new Exception("不允许在根目录外创建文件夹");
        }

        // 2. 创建目录
        FileUtil.mkdir(targetDir);
    }

    // 辅助方法：获取父目录路径
    private String getParentPath(String currentPath) {
        if (StrUtil.isEmpty(currentPath)) {
            return "";
        }
        String[] segments = currentPath.replace("\\", "/").split("/");
        if (segments.length <= 1) {
            return "";
        }
        StringBuilder parent = new StringBuilder();
        for (int i = 0; i < segments.length - 1; i++) {
            if (i > 0) parent.append("/");
            parent.append(segments[i]);
        }
        return parent.toString();
    }

    // 辅助方法：校验路径是否在根目录内
    private boolean isPathInRoot(File target, File root) throws IOException {
        String targetPath = target.getCanonicalPath();
        String rootPath = root.getCanonicalPath();
        return targetPath.startsWith(rootPath);
    }
}